package aa.wl;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Hashtable;

import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import weblogic.management.mbeanservers.edit.ActivationTaskMBean;

// import com.healthnet.plugins.hn_wls_configurator.pojo.ActivationTaskPOJO;

// import com.healthnet.plugins.hn_wls_configurator.pojo.ActivationTaskPOJO;

public abstract class AbstractJMXWorker {
	// MSbeans Servers
	private static String _MBEANS_SERVER_RUNTIME = "weblogic.management.mbeanservers.runtime";
	private static String _MBEANS_SERVER_EDIT = "weblogic.management.mbeanservers.edit";
	private static String _MBEANS_SERVER_DOMAINRUNTIME = "weblogic.management.mbeanservers.domainruntime";
	// Root MBeans
	private static final String _EDIT_MBEAN = "com.bea:Name=EditService,Type=weblogic.management.mbeanservers.edit.EditServiceMBean";
	protected MBeanServerConnection connection;
	protected ObjectName service;
	private static JMXConnector connector;
	private String protocol = "t3";
	// Get an object name for the Configuration Manager.
	protected ObjectName cfgMgr = null;
	protected ObjectName cfgRoot = null;

	/**
	 * ------------------------------------- Initializes service and cfgMgr
	 * 
	 * @throws AttributeNotFoundException
	 * @throws InstanceNotFoundException
	 * @throws MBeanException
	 * @throws ReflectionException
	 * @throws IOException
	 */
	public AbstractJMXWorker() throws AttributeNotFoundException,
			InstanceNotFoundException, MBeanException, ReflectionException,
			IOException {
		// Initializing the object name for EditServiceMBean
		// so it can be used throughout the class.
		try {
			service = new ObjectName(_EDIT_MBEAN);
		} catch (MalformedObjectNameException e) {
			throw new AssertionError(e.getMessage());
		}
	}

	/**
	 * ----------------------- Initialize connection to the Edit MBean Server.
	 * 
	 * @param hostname
	 * @param portString
	 * @param username
	 * @param password
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	@SuppressWarnings("unchecked")
	public MBeanServerConnection initConnection(String hostname,
			String portString, String username, String password)
			throws IOException, MalformedURLException {

		Integer portInteger = Integer.valueOf(portString);
		int port = portInteger.intValue();
		String jndiroot = "/jndi/";
		String mserver = _MBEANS_SERVER_EDIT;

		JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port,
				jndiroot + mserver);

		Hashtable h = new Hashtable();
		h.put(Context.SECURITY_PRINCIPAL, username);
		h.put(Context.SECURITY_CREDENTIALS, password);
		h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
				"weblogic.management.remote");
		connector = JMXConnectorFactory.connect(serviceURL, h);
		MBeanServerConnection connection = connector.getMBeanServerConnection();

		return connection;
	}

	/**
	 * ------------------------------------------------- Start an edit session.
	 */
	public ObjectName startEditSession(MBeanServerConnection connection)
			throws Exception {
		if (connection == null)
			throw new Exception("Connection null");
		// Get the object name for ConfigurationManagerMBean.
		this.cfgMgr = (ObjectName) connection.getAttribute(service,
				"ConfigurationManager");

		// Instruct MBeanServerConnection to invoke
		// ConfigurationManager.startEdit(int waitTime int timeout).
		// The startEdit operation returns a handle to DomainMBean, which is
		// the root of the edit hierarchy.
		ObjectName domainConfigRoot = (ObjectName) connection.invoke(cfgMgr,
				"startEdit", new Object[] { new Integer(60000),
						new Integer(120000) }, new String[] {
						"java.lang.Integer", "java.lang.Integer" });
		if (domainConfigRoot == null) {
			// Couldn't get the lock
			throw new Exception("Somebody else is editing already");
		}
		return domainConfigRoot;
	}

	/**
	 * ------------------------------------------------------ Save and Activate.
	 * 
	 * @throws IOException
	 * 
	 * @throws Exception
	 */
	public ActivationTaskPOJO saveActivateClose() throws IOException {
		int status_code = 0;
		ActivationTaskPOJO status = new ActivationTaskPOJO();
		try {
			save();
			status = activate();
			// If activation is ok purge them to free memory
			// connection.invoke(cfgMgr, "purgeCompletedActivationTasks", null,
			// null);
		} catch (MBeanException e) {
			e.printStackTrace();
		} catch (InstanceNotFoundException e) {
			e.printStackTrace();
		} catch (ReflectionException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			connector.close();
		}

		return status;
	}

	public void cancelEdit() throws InstanceNotFoundException, MBeanException,
			ReflectionException, IOException {
		// mojo.getConnection().invoke(cfgMgr, "cancelEdit", null, null);
	}

	/**
	 * ------------------------------------------------------ Save.
	 * 
	 * @throws InstanceNotFoundException
	 * @throws MBeanException
	 * @throws ReflectionException
	 * @throws IOException
	 */
	protected void save() throws InstanceNotFoundException, MBeanException,
			ReflectionException, IOException {
		try {
			connection.invoke(cfgMgr, "save", null, null);
		} catch (MBeanException e) {
			connection.invoke(cfgMgr, "undo", null, null);
		} catch (ReflectionException e) {
			connection.invoke(cfgMgr, "undo", null, null);
		} catch (InstanceNotFoundException e) {
			connection.invoke(cfgMgr, "undo", null, null);
		} catch (IOException e) {
			connection.invoke(cfgMgr, "undo", null, null);
		}
	}

	/**
	 * ---------------------------------------------------------- activate edits
	 * 
	 * ----------------------------------------------------------
	 */
	protected ActivationTaskPOJO activate() throws Exception {
		ActivationTaskPOJO status = new ActivationTaskPOJO();
		// Get the object name for ConfigurationManagerMBean.
		ObjectName cfgMgr = (ObjectName) connection.getAttribute(service,
				"ConfigurationManager");
		// Instruct MBeanServerConnection to invoke
		// ConfigurationManager.activate(long timeout).
		// The activate operation returns an ActivationTaskMBean.
		// You can use the ActivationTaskMBean to track the progress
		// of activating changes in the domain.
		ObjectName activate = (ObjectName) connection.invoke(cfgMgr,
				"activate", new Object[] { new Long(120000) },
				new String[] { "java.lang.Long" });
		connection.invoke(activate, "waitForTaskCompletion", null, null);
		Integer state = ActivationTaskMBean.STATE_NEW;

		while (state <= ActivationTaskMBean.STATE_PENDING) {
			// state = (Integer) connection.getAttribute(activate, "State");
			state = (Integer) connection.getAttribute(activate, "State");
			System.out.println(state.toString());
			if (state == 5) {
				status.setErrorStr((String) connection.getAttribute(activate,
						"Error"));
			}

			Thread.sleep(3600);
		}

		switch (state) {
		case ActivationTaskMBean.STATE_NEW:
			status.setStatusStr("NEW");
			break;
		case ActivationTaskMBean.STATE_DISTRIBUTING:
			status.setStatusStr("DISTRIBUTING");
			break;
		case ActivationTaskMBean.STATE_DISTRIBUTED:
			status.setStatusStr("DISTRIBUTED");
			break;
		case ActivationTaskMBean.STATE_PENDING:
			status.setStatusStr("PENDING");
			break;
		case ActivationTaskMBean.STATE_COMMITTED:
			status.setStatusStr("COMMITTED");
			break;
		case ActivationTaskMBean.STATE_FAILED:
			status.setStatusStr("FAILED");
			break;
		case ActivationTaskMBean.STATE_CANCELING:
			status.setStatusStr("CANCELING");
			break;
		case ActivationTaskMBean.STATE_COMMIT_FAILING:
			status.setStatusStr("COMMIT_FAILING");
			break;

		default:
			status.setStatusStr("UNKNOWN");
			break;
		}

		return status;
	}

	public MBeanServerConnection getConnection() {
		return connection;
	}

	public ObjectName[] getServerRuntimes() throws Exception {
		return (ObjectName[]) connection
				.getAttribute(service, "ServerRuntimes");
	}

	public void editAdminServerNote(ObjectName cfgRoot, String newNotes)
			throws Exception {
		ObjectName[] dataSource_on = (ObjectName[]) connection.getAttribute(
				cfgRoot, "JDBCSystemResources");
		Attribute adminport = new Attribute("Notes", newNotes);
		connection.setAttribute(dataSource_on[0], adminport);
		System.out.println("Changed the Admin Console Notes");
	}
}
